#include <stdio.h>
#include <stdint.h>
#include "sys_app.h"
#include "esp_log.h"
#include "msg_manager.h"
#include "task_manager.h"

#define TAG "SYS_APP"

struct app_task_handle_t {
    uint8_t sta_process;
    sys_app_t cur_app;
    sys_app_t last_app;
};

static struct app_task_handle_t app_task_handle;

sys_app_t sys_get_cur_app(void)
{
    return app_task_handle.cur_app;
}

void sys_reset_app_null(struct app_msg* msg)
{
    app_task_handle.cur_app = SYS_APP_NULL;
}

static void null_app_loop(void *arg)
{
    struct app_msg* msg = NULL;

    while (sys_get_cur_app() == SYS_APP_NULL) {
        if (msg_manager_receive_msg(&msg, portMAX_DELAY)) {
            ESP_LOGI(TAG, "%s: receive msg type: %d, cmd: %d, value: %08x", __func__, msg->type, msg->cmd, msg->value);
            switch (msg->type) {
                case MSG_START_APP:
                {
                    struct app_msg new_msg = {0};
                    
                    app_task_handle.cur_app = (sys_app_t)msg->value;

                    new_msg.type = MSG_INIT_APP;
                    new_msg.value = app_task_handle.cur_app;
                    msg_manager_send_async_msg(APP_TASK_NAME, &new_msg);
                }
                break;

                default:
                break;
            }
            msg_manager_receive_exit(msg);
        }
    }
}

static void sys_app_task_init(void)
{
    app_task_handle.cur_app = SYS_APP_NULL;

    msg_manager_init();
}

static void sys_app_task_exit(void)
{
    msg_manager_deinit();
}

void sys_app_task(void *pvParameters)
{
    ESP_LOGI(TAG, "sys_app_task start");

    sys_app_task_init();

    while (1) {
        switch (app_task_handle.cur_app) {
            case SYS_APP_BTMUSIC:
                ESP_LOGI(TAG, "SYS_APP_BTMUSIC");
                btmusic_main_loop(pvParameters);
                break;

            case SYS_APP_LCMUSIC:
                ESP_LOGI(TAG, "SYS_APP_LCMUSIC");
                lcmusic_main_loop(pvParameters);
                break;

            case SYS_APP_RECORD:
                ESP_LOGI(TAG, "SYS_APP_RECORD");
                record_main_loop(pvParameters);
                break;

            default:
                ESP_LOGI(TAG, "SYS_APP_NULL");
                null_app_loop(pvParameters);
                break;
        }
    }

    sys_app_task_exit();
}

void sys_app_entry(sys_app_t app)
{
    if (app == app_task_handle.cur_app) {
        ESP_LOGW(TAG, "app %d is already running", app);
        return;
    }

    struct app_msg msg = {0};

    app_task_handle.last_app = app_task_handle.cur_app;

    if (app_task_handle.cur_app != SYS_APP_NULL) {
        app_task_handle.cur_app = SYS_APP_NULL;

        msg.type = MSG_EXIT_APP;
        msg.value = app_task_handle.cur_app;

        msg_manager_send_sync_msg(APP_TASK_NAME, &msg, NULL);
    }

    msg.type = MSG_START_APP;
    msg.value = app;

    msg_manager_send_async_msg(APP_TASK_NAME, &msg);
}

void sys_app_quit(sys_app_t app)
{
    if (app != app_task_handle.cur_app) {
        ESP_LOGW(TAG, "app %d is not running", app);
        return;
    }

    struct app_msg msg = {0};

    app_task_handle.last_app = app_task_handle.cur_app;

    msg.type = MSG_EXIT_APP;
    msg.value = app;
    msg.callback = sys_reset_app_null;

    msg_manager_send_async_msg(APP_TASK_NAME, &msg);
}

void sys_app_switch()
{
    sys_app_t cur_app = (app_task_handle.cur_app + 1) % SYS_APP_MAX;
    if (cur_app == SYS_APP_NULL) {
        cur_app = SYS_APP_NULL + 1;
    }
    sys_app_entry(cur_app);
}
